/***************************************************************************************
  *Copyright(C),2010-2016,Sumscope
  *FileName   : TableSorter.cpp
  *Author     : scofined.qi
  *Version    : 1.0
  *Date       : 2016/06/02
  *Desc       : //用于说明此程序文件完成的主要功能
  *Relation   :
  *Other      : //其他内容说明
  *Function   : //主要函数列表，每条记录应包含函数名及功能简要说明
  *History    : //修改历史纪录列表，每条修改记录应包含修改日期，修改者以及修改内容简介
  ***************************************************************************************/

#include "TableSorter.h"
#include "TableUser.h"
#include "Table.h"
#include "ThreadPool.h"
#include "SortBuffer.h"
#include "SortTask.h"
#include <algorithm>

#ifdef WIN32
#define BASSERT assert
#else
#define BASSERT //
#endif

using namespace qb::base;
namespace qb{
	namespace ht{
		//////////////////////////////////////////////////////////////////////////
		TableSorter::TableSorter() :
			m_comp_level(0),
			m_sequential_mode(true)
		{
			m_sort_buffer = new SortBuffer();
			m_task_cache = new TaskCache();
		}

		TableSorter::~TableSorter()
		{
			if (m_sort_buffer){ delete m_sort_buffer; }
			if (m_comp_temp){ delete[] m_comp_temp; }
			if (m_task_cache){ delete m_task_cache; }
		}

		//////////////////////////////////////////////////////////////////////////
		void TableSorter::SortColumns(Table* table, TableUser* user)
		{
			/*
				1.LoadSortColumns 加载要排序列的数据和rid到整块内存构成表格
				2.ThreadSort使用若干个子线程对此表格进行排序
				1).检测异常情况,并通知线程池进入快速模式(等待时间更短)
				2).主线程划分排序段
				3).主线程将排序段分给线程池中的子线程进行排序
				4).主线程挑取最开头的1024个记录进行排序
				5).主线程等待所有子线程完成
				3.将排序好的row-rid映射关系更新到user中
				4.可选：检查排序是否正确
				*/
			// 根据user的多列信息，准备排序器
			{
				//CMETRICS("LoadSortColumns");

				LoadSortColumns(table, user);
			}

			int ncount = m_sort_buffer->GetRecordCount();
			int nsize = m_sort_buffer->GetRecordSize();
			{
				PrepareTempBuffer(nsize);
			}
			

			// 排序复用，排序缓存
			// 当两次排序的sortbuffer相同的时候，将采用相同的结果
			// 首先得 判断相同的场景是否普遍
			m_comp_level = m_sort_buffer->m_columns.size();
			sort_ = (unsigned char*)m_sort_buffer->GetBuffer();

			class Comparator{
				TableSorter&	m_sorter;
			public:
				Comparator(TableSorter& sb) :m_sorter(sb){}
				bool operator()(const INDEX& i1, const INDEX& i2)
				{
					return m_sorter.CompareRecord(i1, i2) < 0;
				}
			};
			{
				std::sort(m_indexes.begin(), m_indexes.end(), Comparator(*this));
			}

			if (0)
			{
				int cmp_count = comp_count_;
				int swap_count = swap_count_;
                //DWORD start = GetTickCount();
				//CMETRICS("ThreadSort");
                //HighResTime timer;

				// 这里有三种排序方法都可用,只是比较哪个更快
				//ThreadSort((char*)sort_, ncount, nsize, &TableSorter::StaticCompareColumns);
				//QuickSort((char*)sort_, ncount, nsize, &TableSorter::StaticCompareColumns);
				//qsort_s((char*)sort_, ncount, nsize, &TableSorter::StaticCompareColumns2,this);
				//BVIEW(0, 0, 0, "sort last %.6f-%d ncount:%d comp:%d  swap:%d",
				//	timer.elapsed(), GetTickCount() - start, ncount,
				//	comp_count_ - cmp_count, swap_count_ - swap_count);

				/*
					6w条记录，排序 bondkey，nstring,测试结果
					ThreadSort		0.0468005
					QuickSort		0.011428s
					qsort_s			0.012834s
					*/
			}

			{
				user->UpdateIndex(m_indexes);
			}
			
		}
		bool TableSorter::PrepareTempBuffer(int nsize)
		{
            BASSERT(nsize > 4);
			if (m_temp_size < nsize || m_comp_temp == 0)
			{
				if (m_comp_temp)	delete[] m_comp_temp;
				m_comp_temp = new char[nsize + 1];
				memset(m_comp_temp, 0, nsize + 1);
			}
			m_record_size = nsize;
			m_temp_size = m_temp_size < nsize ? nsize : m_temp_size;
            BASSERT(m_temp_size >= nsize);
            BASSERT(m_comp_temp);
			return true;
		}


		void TableSorter::LoadSortColumns(Table* table, TableUser* user)
		{
			// 将表格table的用户user的多重排序信息暂存在m_sort_buffer中
			m_sort_buffer->CLearColumns();
			const ColumnVec& sortcolumns = user->GetSortColumns();
			for (int i = 0; i < (int)sortcolumns.size(); i++)
			{
				int col = sortcolumns[i];
				m_sort_buffer->AddColumn(table->GetColumnInfo(col), user->GetColumnDecFlag(i));
			}

			int rcount = user->GetRecordCount();
			char* buf = m_sort_buffer->PrepareBuffer(rcount);
			int size = m_sort_buffer->GetRecordSize();
			char* precord = buf;

			if (m_sequential_mode)
			{
				// 将rowmap按照rid排序，将随机读取变为顺序读取, 使得映射文件的SSMapViewOfFile调用次数更少
				// 具体改善多少，需要将两部分代码进行对比测试
				{
					m_sequential_rows.clear();
					m_sequential_rows.reserve(rcount);
					TableUser::KeyIterator it = user->GetBegin();
					TableUser::KeyIterator end = user->GetEnd();
					for (int i = 0; i < rcount && it != end; ++i, ++it)
					{
						const TableUser::RecordKey& key = *it;
						*(int*)(precord) = key.rid;
						RowIndex rindex; rindex.row = i, rindex.rid = key.rid;
						m_sequential_rows.push_back(rindex);
					}
				}

				RowIndex* rows = &m_sequential_rows.at(0);
				{
					qsort(rows, rcount, sizeof(RowIndex), RowIndex::Compare);
				}
				

				{
					m_indexes.clear();
					m_indexes.reserve(rcount);
					int offset = 0;
					for (int i = 0; i < rcount; i++, offset += size)
					{
						INDEX idx(rows[i].rid, offset);
						m_indexes.push_back(idx);
						table->ReadColumns(idx.rid, sortcolumns, buf + idx.offset, size);
					}
				}
			}
			else
			{
				m_indexes.clear();
				m_indexes.reserve(rcount);
				int offset = 0;
				TableUser::KeyIterator it = user->GetBegin();
				TableUser::KeyIterator end = user->GetEnd();
				for (int offset = 0; it != end; ++it, offset+=size)
				{
					const TableUser::RecordKey& key = *it;
					INDEX idx(key.rid, offset);
					m_indexes.push_back(idx);
					table->ReadColumns(idx.rid, sortcolumns, buf + idx.offset, size);
				}
			}
		}
		int TableSorter::CompareRecord(const INDEX& k1, const INDEX& k2)
		{
			int cmp = 0;
			for (int i = 0; i < m_comp_level; ++i)
			{
				ColumnInfo& ci = m_sort_buffer->m_columns[i];
				cmp = ci.m_comp(sort_ + k1.offset + ci.m_offset, sort_ + k2.offset + ci.m_offset);
				cmp = ci.m_dec ? -cmp : cmp;
				if (cmp != 0)
					return cmp;
			}
			return cmp;
		}

		int TableSorter::CompareColumns(const void* pSortData1, const void* pSortData2)
		{
			//comp_count_++;
			int ret = 0;
			for (int i = 0; i < m_comp_level; ++i)
			{
				ColumnInfo& ci = m_sort_buffer->m_columns[i];
				ret = ci.m_comp((const char*)pSortData1 + ci.m_offset, (const char*)pSortData2 + ci.m_offset);
				if (ret != 0)
					return ci.m_dec ? -ret : ret;
			}
			return 0;
		}
	}//namespace ht
}//namespace qb
